
package com.greencat.gwt.comet.server;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import com.greencat.gwt.comet.server.impl.GwtAtmosphereResourceImpl;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.atmosphere.cpr.AtmosphereResource;
import org.atmosphere.cpr.AtmosphereServlet;

/**
 *
 * @author p.havelaar
 */
public class GwtAtmosphereServlet extends HttpServlet {

    private static final int DEFAULT_HEARTBEAT = 15 * 1000; // 15 seconds by default

    protected final Log logger = LogFactory.getLog(getClass());

    @Override
    public void init() throws ServletException {
        ServletConfig servletConfig = getServletConfig();
		String heartbeat = servletConfig.getInitParameter("heartbeat");
		if (heartbeat != null) {
			this.heartbeat = Integer.parseInt(heartbeat);
		}
    }

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        AtmosphereResource<HttpServletRequest, HttpServletResponse> atm
                = (AtmosphereResource<HttpServletRequest, HttpServletResponse>)
                request.getAttribute(AtmosphereServlet.ATMOSPHERE_RESOURCE);
        
        if (atm == null) {
            throw new ServletException("Failed to get atmosphere resource. " +
                    "Did you setup atmosphere.xml correctly?");
        }
        try {
			int requestHeartbeat = heartbeat;
			String requestedHeartbeat = request.getParameter("heartbeat");
			if (requestedHeartbeat != null) {
				try {
					requestHeartbeat = Integer.parseInt(requestedHeartbeat);
					if (requestHeartbeat <= 0) {
						throw new IOException("invalid heartbeat parameter");
					}
					requestHeartbeat = computeHeartbeat(requestHeartbeat);
				}
				catch (NumberFormatException e) {
					throw new IOException("invalid heartbeat parameter");
				}
			}

            GwtAtmosphereResourceImpl resource = new GwtAtmosphereResourceImpl(atm, this, requestHeartbeat);
			doCometImpl(resource);
		}
		catch (IOException e) {
//            GwtAtmosphereResourceImpl resource = new GwtAtmosphereResourceImpl(atm, this, -1);
            logger.error("Unable to initiated comet" + e.getMessage(), e);
//			resource.getResponseWriter().sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage());
		}
    }

    public  int doComet(GwtAtmosphereResource resource) throws ServletException, IOException {
        return -1;
    }

    public void cometTerminated(GwtAtmosphereResource cometResponse, boolean serverInitiated) {
    }
    
    protected int computeHeartbeat(int requestedHeartbeat) {
		return requestedHeartbeat < heartbeat ? heartbeat : requestedHeartbeat;
	}

	private void doCometImpl(GwtAtmosphereResourceImpl resource) throws IOException {

        try {
			// setup the request
			resource.getWriterImpl().initiate();
        } catch (IOException e) {
            logger.error("Error initiating GwtComet", e);
            return;
        }

        int timeout;
        try {
			// call the application code
			timeout = doComet(resource);
		}
        catch (ServletException e) {
            logger.error("Error calling doComet()", e);
//			resource.getResponseWriter().sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
            return;
        }
		catch (IOException e) {
			logger.error("Error calling doComet()", e);
//			resource.getResponseWriter().sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
            return;
		}

		// at this point the application may have spawned threads to process this response
		// so we have to be careful about concurrency from here on
		resource.suspend(timeout);
	}
	
    private int heartbeat = DEFAULT_HEARTBEAT;
}
